#include "wifi_execute.h"
#include <cJSON.h>
#include "file_op.h"
#include "led_op.h"
#include "ntpc.h"
#include "configs.h"

const char *STA_SSID = NULL;
const char * STA_PASSWORD = NULL;

const char *AP_SSID = "ai-thinker";
const char *AP_PWD = "12345678";

#define TAG "softAP"

static wifi_conf_t conf = {
    .country_code = "CN",
};

country_code_type country_code = WIFI_COUNTRY_CODE_CN;
static wifi_interface_t g_wifi_sta_interface = NULL;
static int g_wifi_sta_is_connected = 0;
static int ap_started = 0;
// wifi_sta_reconnect_t sta_reconn_params = {60, 10}; // set connection interval = 15, reconntction times = 10
static wifi_interface_t ap_interface;

void set_wifi_connected(int is_connected)
{
    g_wifi_sta_is_connected = is_connected;
}

void set_ap(const char *ssid, const char *pwd)
{
    AP_SSID = ssid;
    AP_PWD = pwd;
}

void set_sta(const char *ssid, const char *pwd)
{
    STA_SSID = ssid;
    STA_PASSWORD = pwd;
}

static void wifi_sta_connect(void)
{
    static int retry_count = 2;

    if ((g_wifi_sta_is_connected != 1) && (STA_SSID != NULL) && (retry_count > 0)) {
        // wifi_mgmr_sta_disable(g_wifi_sta_interface);
        g_wifi_sta_interface = wifi_mgmr_sta_enable();
        // wifi_mgmr_sta_autoconnect_enable();
        wifi_mgmr_sta_autoconnect_disable();
        printf("connect to wifi %s\n", STA_SSID);
        wifi_mgmr_sta_connect(g_wifi_sta_interface, STA_SSID, STA_PASSWORD, NULL, NULL, 0, 0);
        retry_count--;
    }

    if (retry_count <= 0) {
        led_clear_status(LED_STAT_NO_NETWORK);
    }
}

static void wifi_ap_ip_set(char* ip_addr, char* netmask, char* gw)
{
    struct netif* ap_netif = netif_find("ap1");
    int i = 0;
    int ap_ipaddr[4] = { 0 };
    int ap_netmask[4] = { 255,255,255,0 };
    int ap_gw_arry[4] = { 0,0,0,0 };

    ap_ipaddr[0] = atoi(strtok(ip_addr, "."));

    for (i = 1; i<4;i++) {
        ap_ipaddr[i] = atoi(strtok(NULL, "."));
    }
    if (netmask) {
        ap_netmask[0] = atoi(strtok(netmask, "."));
        for (i = 1;i<4;i++)
            ap_netmask[i] = atoi(strtok(NULL, "."));
    }
    if (gw) {
        ap_gw_arry[0] = atoi(strtok(gw, "."));
        for (i = 1;i<4;i++)
            ap_gw_arry[i] = atoi(strtok(NULL, "."));
    }

    if (ap_netif) {
        ip_addr_t ap_ip;
        ip_addr_t ap_mask;
        ip_addr_t ap_gw;
        IP4_ADDR(&ap_ip, ap_ipaddr[0], ap_ipaddr[1], ap_ipaddr[2], ap_ipaddr[3]);
        IP4_ADDR(&ap_mask, ap_netmask[0], ap_netmask[1], ap_netmask[2], ap_netmask[3]);
        IP4_ADDR(&ap_gw, ap_gw_arry[0], ap_gw_arry[1], ap_gw_arry[2], ap_gw_arry[3]);

        netif_set_down(ap_netif);
        netif_set_ipaddr(ap_netif, &ap_ip);
        netif_set_netmask(ap_netif, &ap_mask);
        netif_set_gw(ap_netif, &ap_gw);
        netif_set_up(ap_netif);
        printf("[softAP]:SSID:%s,PASSWORD:%s,IP addr:%s", AP_SSID, AP_PWD, ip4addr_ntoa(netif_ip4_addr(ap_netif)));
    } else {
        printf("no find netif ap1 ");
    }
}

/**
 * @brief wifi_ap_start
 *
 */
static void wifi_ap_start()
{
    ap_interface = wifi_mgmr_ap_enable();
    wifi_mgmr_conf_max_sta(4);
    wifi_mgmr_ap_start(ap_interface, AP_SSID, 0, AP_PWD, 6);
    wifi_ap_ip_set("192.168.169.1", "255.255.255.0", "192.168.169.1");
}

static void wifi_event_cb(input_event_t *event, void *private_data)
{
    static char *ssid;
    static char *password;

    printf("[APP] [EVT] event->code %d\r\n", event->code);

    printf("[SYS] Memory left is %d Bytes\r\n", xPortGetFreeHeapSize());

    switch (event->code) {
        case CODE_WIFI_ON_AP_STARTED: {
            printf("[APP] [EVT] AP INIT DONE %lld\r\n", aos_now_ms());
            ap_started = 1;
        } break;

        case CODE_WIFI_ON_AP_STOPPED: {
            printf("[APP] [EVT] AP STOP DONE %lld\r\n", aos_now_ms());
            ap_started = 0;
        } break;

        case CODE_WIFI_ON_AP_STA_ADD: {
            printf("[APP] [EVT] AP STA ADD %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_ON_AP_STA_DEL: {
            printf("[APP] [EVT] AP STA DEL %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_ON_INIT_DONE: {
            printf("[APP] [EVT] INIT DONE %lld\r\n", aos_now_ms());
            wifi_mgmr_start_background(&conf);
        } break;

        case CODE_WIFI_ON_MGMR_DONE: {
            printf("[APP] [EVT] MGMR DONE %lld\r\n", aos_now_ms());
            wifi_ap_start();
        } break;

        case CODE_WIFI_ON_SCAN_DONE: {
            printf("[APP] [EVT] SCAN Done %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_ON_DISCONNECT: {
            printf("[APP] [EVT] disconnect %lld\r\n", aos_now_ms());
            led_set_status(LED_STAT_NO_NETWORK);
            g_wifi_sta_is_connected = 0;
        } break;

        case CODE_WIFI_ON_CONNECTING: {
            printf("[APP] [EVT] Connecting %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_CMD_RECONNECT: {
            printf("[APP] [EVT] Reconnect %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_ON_CONNECTED: {
            printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_ON_PRE_GOT_IP: {
            printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
        } break;

        case CODE_WIFI_ON_GOT_IP: {
            printf("[APP] [EVT] GOT IP %lld\r\n", aos_now_ms());
            g_wifi_sta_is_connected = 1;
            led_clear_status(LED_STAT_NO_NETWORK);
        } break;

        case CODE_WIFI_ON_PROV_SSID: {
            printf("[APP] [EVT] [PROV] [SSID] %lld: %s\r\n", aos_now_ms(), event->value ? (const char *)event->value : "UNKNOWN");
            if (ssid) {
                vPortFree(ssid);
                ssid = NULL;
            }
            ssid = (char *)event->value;
        } break;

        case CODE_WIFI_ON_PROV_BSSID: {
            printf("[APP] [EVT] [PROV] [BSSID] %lld: %s\r\n", aos_now_ms(), event->value ? (const char *)event->value : "UNKNOWN");
            if (event->value) {
                vPortFree((void *)event->value);
            }
        } break;

        case CODE_WIFI_ON_PROV_PASSWD: {
            printf("[APP] [EVT] [PROV] [PASSWD] %lld: %s\r\n", aos_now_ms(), event->value ? (const char *)event->value : "UNKNOWN");
            if (password) {
                vPortFree(password);
                password = NULL;
            }
            password = (char *)event->value;
        } break;

        case CODE_WIFI_ON_PROV_CONNECT: {
            printf("connecting to %s:%s...\r\n", ssid, password);
        } break;

        case CODE_WIFI_ON_PROV_DISCONNECT: {
            printf("[APP] [EVT] [PROV] [DISCONNECT] %lld\r\n", aos_now_ms());
        } break;

        default: {
            printf("[APP] [EVT] Unknown code %u, %lld\r\n", event->code, aos_now_ms());
        } break;
    }
}

static void wifi_execute(void *pvParameters)
{
    char *buf = (char *)malloc(1024);
    if (buf == NULL) {
        printf("no mem\r\n");
        return;
    }

    memset(buf, 0, 1024);
    int ret = read_file(CONFIGS_FILE, buf, 1024);
    if (ret > 0) {
        cJSON *respJson = cJSON_Parse(buf);
        cJSON *ssid = cJSON_GetObjectItem(respJson, "ssid");
        cJSON *password = cJSON_GetObjectItem(respJson, "password");
        printf("ssid: %s\r\n", ssid->valuestring);
        printf("password: %s\r\n", password->valuestring);
        set_sta(ssid->valuestring, password->valuestring);
        led_clear_status(LED_STAT_NOT_CONFIG);
    } else {
        led_set_status(LED_STAT_NOT_CONFIG);
    }

    aos_register_event_filter(EV_WIFI, wifi_event_cb, NULL);
    static uint8_t stack_wifi_init = 0;

    if (1 == stack_wifi_init) {
        return;
    }
    stack_wifi_init = 1;
    hal_wifi_start_firmware_task();
    aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0);

    while (!ap_started) {
        vTaskDelay(1000);
    }
    init_ntp();

    while (1) {
        wifi_sta_connect();
        vTaskDelay(60000);
    }
}

void wifi_init(void)
{
    xTaskCreate(wifi_execute, (char *)"wifi execute", 1024 * 3, NULL, 15, NULL);
}